﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Linq;
using System.Text;

namespace Corss_LehaKondr
{
    public class AskCollection : IList, INotifyCollectionChanged, INotifyPropertyChanged
    {
        List<Ask> _asks = new List<Ask>();

        public int Count
        {
            get { return _asks.Count; }
        }
        public bool IsSynchronized
        {
            get { return ((ICollection)_asks).IsSynchronized; }
        }

        public object SyncRoot
        {
            get { return ((ICollection)_asks).SyncRoot; }
        }

        public void CopyTo(Array array, int index)
        {
            ((ICollection)_asks).CopyTo(array, index);
        }

        public virtual void CopyTo(Ask[] array, int index)
        {
            _asks.CopyTo(array, index);
        }

        public virtual Ask this[int index]
        {
            get
            {
                return _asks[index];
            }
            set
            {
                if (value == null)
                    throw new NotImplementedException();

                if (object.ReferenceEquals(_asks[index], value))
                    return;

                if (value.haveOwner)
                    throw new NotImplementedException(); //Занятый чилдрен

                Ask oldAsk = _asks[index];
                _asks[index] = value;

                oldAsk.unregisterOwner(this);
                value.registerOwner(this);

                value.Number = (uint)index + 1;

                OnPropertyChanged(IndexerName);
                OnCollectionChanged(NotifyCollectionChangedAction.Replace, oldAsk, value, index);
            }
        }

        public virtual int Add(Ask element)
        {
            if (element == null)
                throw new NotImplementedException();

            if (element.haveOwner)
                throw new NotImplementedException(); //Занятый чилдрен

            int index = ((IList)_asks).Add(element);

            _asks[index].registerOwner(this);
            _asks[index].Number = (uint)index + 1;

            OnPropertyChanged(CountString);
            OnPropertyChanged(IndexerName);
            OnCollectionChanged(NotifyCollectionChangedAction.Add, element, index);

            return index;
        }

        public virtual int IndexOf(Ask element)
        {
            return _asks.IndexOf(element);
        }

        public virtual void Remove(Ask element)
        {
            int index = _asks.IndexOf(element);

            if (_asks.Remove(element))
            {
                element.unregisterOwner(this);

                OnPropertyChanged(CountString);
                OnPropertyChanged(IndexerName); 
                OnCollectionChanged(NotifyCollectionChangedAction.Remove, element, index);
            }
        }

        public virtual bool Contains(Ask element)
        {
            return _asks.Contains(element);
        }

        public void Clear()
        {
            List<Ask> clone = new List<Ask>(_asks);
            _asks.Clear();

            foreach (var item in clone)
                item.unregisterOwner(this);

            OnPropertyChanged(CountString);
            OnPropertyChanged(IndexerName); 
            OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
        }

        public virtual void Insert(int index, Ask element)
        {
            if (element != null)
                throw new NotImplementedException();

            if (element.haveOwner)
                throw new NotImplementedException();

            element.registerOwner(this);
            _asks.Insert(index, element);
            element.Number = (uint)index + 1;

            for (int i = (int)element.Number; i < _asks.Count; i++)
                _asks[i].Number++;

            OnPropertyChanged(CountString);
            OnPropertyChanged(IndexerName); 
            OnCollectionChanged(NotifyCollectionChangedAction.Add, element, index); 
        }

        void IList.RemoveAt(int index)
        {
            Ask ask = _asks[index];

            ask.unregisterOwner(this);

            _asks.RemoveAt(index);

            for (int i = index; i < _asks.Count; i++)
                _asks[i].Number--;

            OnPropertyChanged(CountString);
            OnPropertyChanged(IndexerName); 
            OnCollectionChanged(NotifyCollectionChangedAction.Remove, ask, index);
        }

        public virtual void RemoveRange(int index, int count)
        {
            if (index < 0)
                throw new NotImplementedException();

            if (count > (_asks.Count - index))
            {
                count = _asks.Count - index;
            }

            if (count > 0)
            {
                List<Ask> removed = new List<Ask>();

                for (int i = 0, j = index; i < count; i++, j++)
                    removed.Add(_asks[j]);

                _asks.RemoveRange(index, count);

                for (int i = 0, j = index; i < count; i++, j++)
                {
                    removed[i].unregisterOwner(this);
                    OnCollectionChanged(NotifyCollectionChangedAction.Remove, removed[i], j);
                }

                OnPropertyChanged(CountString);
                OnPropertyChanged(IndexerName); 
            }
        }

        private Ask Cast(object value)
        {
            if (value == null)
                throw new NotImplementedException();

            Ask element = value as Ask;

            if (element == null)
                throw new NotImplementedException();

            return element;
        }

        int IList.Add(object value)
        {
            return Add(Cast(value));
        }

        bool IList.Contains(object value)
        {
            return Contains(value as Ask);
        }

        int IList.IndexOf(object value)
        {
            return IndexOf(value as Ask);
        }
        void IList.Insert(int index, object value)
        {
            Insert(index, Cast(value));
        }

        bool IList.IsFixedSize
        {
            get { return false; }
        }

        bool IList.IsReadOnly
        {
            get { return false; }
        }

        void IList.Remove(object value)
        {
            Remove(value as Ask);
        }

        object IList.this[int index]
        {
            get
            {
                return this[index];
            }
            set
            {

                this[index] = Cast(value);
            }
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return _asks.GetEnumerator();
        }

        protected virtual void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
        {
            if (CollectionChanged != null)
                CollectionChanged(this, e);
        }

        private void OnCollectionChanged(NotifyCollectionChangedAction action, object item, int index)
        {
            OnCollectionChanged(new NotifyCollectionChangedEventArgs(action, item, index));
        }

        private void OnCollectionChanged(NotifyCollectionChangedAction action, object item, int index, int oldIndex)
        {
            OnCollectionChanged(new NotifyCollectionChangedEventArgs(action, item, index, oldIndex));
        }

        private void OnCollectionChanged(NotifyCollectionChangedAction action, object oldItem, object newItem, int index)
        {
            OnCollectionChanged(new NotifyCollectionChangedEventArgs(action, newItem, oldItem, index));
        } 

        public event NotifyCollectionChangedEventHandler CollectionChanged;

        private void OnPropertyChanged(string propertyName)
        {
            OnPropertyChanged(new PropertyChangedEventArgs(propertyName));
        }

        protected virtual void OnPropertyChanged(PropertyChangedEventArgs e)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, e);
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;

        private const string CountString = "Count";
        private const string IndexerName = "Item[]";
    }
}
